package com.amarsoft.task;

import com.amarsoft.are.ARE;
import com.amarsoft.are.AREException;
import com.amarsoft.are.lang.ObjectX;
import com.amarsoft.are.lang.StringX;
import com.amarsoft.are.util.xml.Document;
import com.amarsoft.are.util.xml.Element;
import com.amarsoft.task.security.LoginModule;
import com.amarsoft.task.security.login.AnonymousLogin;
import java.io.File;
import java.io.InputStream;
import java.sql.Connection;
import java.util.Iterator;
import java.util.List;

public class TaskBuilder {
	public static Task buildTaskFromXML(InputStream taskStream) {
		try {
			Document doc = new Document(taskStream);
			return buildTaskFromXML(doc);
		} catch (Exception e) {
			ARE.getLog().fatal("Build document from xml stream failed", e);
		}
		return null;
	}

	public static Task buildTaskFromXML(String taskFile) {
		if (taskFile == null)
			return null;
		return buildTaskFromXML(new File(taskFile));
	}

	public static Task buildTaskFromXML(File taskFile) {
		try {
			Document doc = new Document(taskFile);
			return buildTaskFromXML(doc);
		} catch (Exception e) {
			ARE.getLog()
					.fatal("Build document from " + taskFile + " failed", e);
		}
		return null;
	}

	public static Task buildTaskFromXML(Document taskDocument) {
		Task task = new Task();
		Element xTask = taskDocument.getRootElement();
		buildTaskObject(xTask, task);
		task.setParallelRun(Boolean.valueOf(
				xTask.getAttributeValue("parallelRun")).booleanValue());
		task.setTraceOn(Boolean.valueOf(xTask.getAttributeValue("traceOn"))
				.booleanValue());

		Element xLoginModule = xTask.getChild("loginModule");

		if (xLoginModule == null)
			task.setLoginModule(new AnonymousLogin());
		else {
			try {
				buildLoginModule(xLoginModule, task);
			} catch (Exception ex) {
				ARE.getLog().error("Set loginModule error." + ex.getMessage(),
						ex);
			}

		}

		Element xListeners = xTask.getChild("listeners");
		if (xListeners != null) {
			List<?> ll = xListeners.getChildren("listener");
			if (!(ll.isEmpty())) {
				boolean enabled = true;
				for (int i = 0; i < ll.size(); ++i) {
					Element xListener = (Element) ll.get(i);
					String en = xListener.getAttributeValue("enabled");
					if (en != null)
						enabled = StringX.parseBoolean(en);
					enabled = StringX.parseBoolean(en);
					if (!(enabled))
						continue;
					try {
						buildListener(xListener, task);
					} catch (Exception e) {
						ARE.getLog().error("Add Listener error.", e);
					}
				}

			}

		}

		Element xTargets = xTask.getChild("targets");
		List<?> l = xTargets.getChildren("target");
		if (!(l.isEmpty())) {
			boolean enabled = true;
			for (int i = 0; i < l.size(); ++i) {
				Element xTarget = (Element) l.get(i);
				String en = xTarget.getAttributeValue("enabled");
				if (en != null)
					enabled = StringX.parseBoolean(en);
				if (!(enabled))
					continue;
				try {
					buildTarget(xTarget, task);
				} catch (Exception e) {
					ARE.getLog().error("Load Target error.", e);
					task = null;
				}
			}
		}

		return task;
	}

	private static void buildListener(Element xListener, Task task)
			throws InstantiationException, IllegalAccessException,
			ClassNotFoundException {
		String className = xListener.getAttributeValue("listenerClass");
		if (className == null)
			throw new ClassNotFoundException("listenerClass is null!");
		TaskEventListener listener = (TaskEventListener) Class.forName(
				className).newInstance();

		Element xProps = xListener.getChild("extendProperties");
		if (xProps != null) {
			Iterator<?> it = xProps.getChildren("property").iterator();
			while (it.hasNext()) {
				Element xProp = (Element) it.next();
				String n = xProp.getAttributeValue("name");
				if (n == null)
					continue;
				if (!(n.equals("")))
					;
				n = n.trim();
				ObjectX.setPropertyX(listener, n,
						xProp.getAttributeValue("value"), false);
			}
		}
		task.addTaskEventListener(listener);
	}

	private static void buildLoginModule(Element xLoginModule, Task task)
			throws InstantiationException, IllegalAccessException,
			ClassNotFoundException {
		String className = xLoginModule.getAttributeValue("loginModuleClass");
		if (className == null)
			throw new ClassNotFoundException("LoginModuleClass is null!");
		LoginModule loginModule = (LoginModule) Class.forName(className)
				.newInstance();

		Element xProps = xLoginModule.getChild("extendProperties");
		if (xProps != null) {
			Iterator<?> it = xProps.getChildren("property").iterator();
			while (it.hasNext()) {
				Element xProp = (Element) it.next();
				String n = xProp.getAttributeValue("name");
				if (n == null)
					continue;
				if (!(n.equals("")))
					;
				n = n.trim();
				ObjectX.setPropertyX(loginModule, n,
						xProp.getAttributeValue("value"), false);
			}
		}
		task.setLoginModule(loginModule);
	}

	private static void buildTarget(Element xTarget, Task task)
			throws InstantiationException, IllegalAccessException,
			ClassNotFoundException, AREException {
		Target target = new Target();
		buildTaskObject(xTarget, target);
		target.setParallelRun(Boolean.valueOf(
				xTarget.getAttributeValue("parallelRun")).booleanValue());
		String parallelNumber = xTarget.getAttributeValue("parallelNumber");
		if (parallelNumber != null) {
			target.setParallelNumber(xTarget
					.getAttributeValue("parallelNumber"));
		}
		Element xUnits = xTarget.getChild("executeUnits");
		if (xUnits == null) {
			throw new AREException("Target: " + target.getName()
					+ " miss executeUnits node!");
		}

		Iterator<?> it = xUnits.getChildren("executeUnit").iterator();
		while (it.hasNext()) {
			Element xUnit = (Element) it.next();
			buildUnit(xUnit, target);
		}

		Element xRouteTable = xTarget.getChild("routeTable");
		if ((xRouteTable == null) && (!(target.isParallelRun()))) {
			throw new AREException("Target: " + target.getName()
					+ " miss routeTable node!");
		}

		buildRoute(target, xRouteTable);

		Element xParallelTable = xTarget.getChild("parallelTable");
		if (xParallelTable == null) {
			if (target.isParallelRun()) {
				throw new AREException("Target: " + target.getName()
						+ " miss parallelTable node!");
			}
		} else {
			buildParallelTable(target, xParallelTable);
		}
		task.addTarget(target);
	}

	private static void buildRoute(Target target, Element xRouteTable)
			throws IllegalAccessException {
		Iterator<?> it = xRouteTable.getChildren("route").iterator();
		while (it.hasNext()) {
			Element xRoute = (Element) it.next();
			ExecuteUnit unit = target.getUnit(xRoute.getAttributeValue("unit"));
			if (unit == null) {
				throw new IllegalAccessException("Illegal route,unit \""
						+ xRoute.getAttributeValue("unit") + "\" not access!");
			}

			ExecuteUnit nextUnit = target.getUnit(xRoute
					.getAttributeValue("nextUnit"));
			if (nextUnit == null) {
				throw new IllegalAccessException("Illegal route,nextUnit \""
						+ xRoute.getAttributeValue("nextUnit")
						+ "\" not access!");
			}

			String attrExecuteStatus = xRoute
					.getAttributeValue("executeStatus");
			if ((attrExecuteStatus == null)
					|| (attrExecuteStatus.equalsIgnoreCase(""))) {
				throw new IllegalAccessException(
						"Illegal route,lost executeStatus,unit=\""
								+ xRoute.getAttributeValue("unit")
								+ "\",nextUnit=\""
								+ xRoute.getAttributeValue("nextUnit") + "\"");
			}

			unit.addRoute(new Route(attrExecuteStatus, nextUnit));
		}
	}

	private static void buildParallelTable(Target target, Element xRouteTable)
			throws IllegalAccessException {
		Iterator<?> it = xRouteTable.getChildren("unit").iterator();
		while (it.hasNext()) {
			Element xUnit = (Element) it.next();
			ExecuteUnit unit = target.getUnit(xUnit.getAttributeValue("name"));
			if (unit == null){
				throw new IllegalAccessException("Illegal route,unit \""
						+ xUnit.getAttributeValue("name") + "\" not access!");
			}
			target.getParalleTable().addUnit(unit);

			Iterator<?> itp = xUnit.getChildren("preUnit").iterator();
			while (itp.hasNext()) {
				Element xPreUnit = (Element) itp.next();
				ExecuteUnit preUnit = target.getUnit(xPreUnit
						.getAttributeValue("unit"));
				if (preUnit == null)
					throw new IllegalAccessException("Illegal route,unit \""
							+ xPreUnit.getAttributeValue("name")
							+ "\" not access!");
				String attrExecuteStatus = xPreUnit
						.getAttributeValue("executeStatus");
				if ((attrExecuteStatus == null)
						|| (attrExecuteStatus.equalsIgnoreCase("")))
					throw new IllegalAccessException(
							"Illegal preUnit,lost executeStatus,unit=\""
									+ xPreUnit.getAttributeValue("unit") + "\"");
				target.getParalleTable().addPreviousUnit(unit, preUnit,
						attrExecuteStatus);
			}
		}
		ARE.getLog().debug("\n" + target.getParalleTable());
	}

	private static void buildUnit(Element xUnit, Target target)
			throws InstantiationException, IllegalAccessException,
			ClassNotFoundException {
		String className = xUnit.getAttributeValue("executeClass");
		if (className == null) {
			className = xUnit.getChildTextTrim("executeClass");
		}
		ExecuteUnit unit = (ExecuteUnit) Class.forName(className).newInstance();
		buildTaskObject(xUnit, unit);
		String at = xUnit.getAttributeValue("allowManualExecute");
		if (at != null)
			unit.setAllowManualExecute(StringX.parseBoolean(at));
		target.addUnit(unit);
	}

	private static void buildTaskObject(Element objectElement, TaskObject object) {
		String sa = objectElement.getAttributeValue("name");
		if (sa == null)
			sa = objectElement.getChildTextTrim("name");
		object.setName(sa);

		sa = objectElement.getAttributeValue("describe");
		if (sa == null)
			sa = objectElement.getChildTextTrim("describe");
		object.setDescribe(sa);

		Iterator<?> it = null;

		Element xProps = objectElement.getChild("extendProperties");
		Element xProp;
		if (xProps != null) {
			it = xProps.getChildren("property").iterator();
			while (it.hasNext()) {
				xProp = (Element) it.next();
				object.setProperty(xProp.getAttributeValue("name"),
						xProp.getAttributeValue("value"));
			}

		}

		it = objectElement.getChildren("property").iterator();
		while (it.hasNext()) {
			xProp = (Element) it.next();
			object.setProperty(xProp.getAttributeValue("name"),
					xProp.getAttributeValue("value"));
		}
	}

	public static Task buildTaskFromDB(Connection connection, String taskTable,
			String targetTable, String procedureTable) {
		return null;
	}

	public static Task buildTaskFromFile(String filename) {
		return null;
	}
}